import {
    _decorator, Component, input, Input, instantiate, LabelComponent, Node,
    Prefab, UITransform, Vec2, Tween, Vec3, easing, NodeEventType, SystemEvent
} from 'cc';
import { Tile } from './Tile';
const { ccclass, property } = _decorator;
enum Direction {
    UP = 1,
    DOWN = 2,
    LEFT = 3,
    RIGHT = 4
}

@ccclass('Game')
export class Game extends Component {

    @property(Node)
    startPanel: Node = null!;
    @property(Node)
    gamePanel: Node = null!;

    @property(LabelComponent)
    private scoreLabel: LabelComponent = null;
    @property(LabelComponent)
    private bestLabel: LabelComponent = null;
    @property(Node)
    private gridBg: Node = null;
    @property(UITransform)
    private gridBgUITransform: UITransform = null;
    @property(Prefab)
    private grid: Prefab = null;
    @property(Prefab)
    private gridbg: Prefab = null;

    private UserData: any = null;

    private grids: number = 4; // 行数 列表
    private jiange: number = 20;
    private itemWidth: number = 0;
    private gridWidth: number = 580;
    private data = []

    private posStart: Vec2 = null;
    private posEnd: Vec2 = null;

    private panel: number = 0;


    start() {
        console.log('start')
        this.initPanel();
        this.startPanel.active = true;

        this.addTouch();
    }

    /**
     * 触摸事件
     */
    private addTouch() {
        // 手势事件
        this.node.on(NodeEventType.TOUCH_START, this.onTouchStart, this);
        this.node.on(NodeEventType.TOUCH_END, this.onTouchEnd, this);

        // 键盘事件
        input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
    }

    /**
     * 按键事件
     * @param event 
     * @returns 
     */
    private onKeyDown(event: any) {
        if (this.panel == 0) return;
        switch (event.keyCode) {
            case 37: // 左箭头键
            case 65: // A键
                this.moveItem(Direction.LEFT);
                break;
            case 38: // 上箭头键
            case 87: // W键
                this.moveItem(Direction.UP);
                break;
            case 39: // 右箭头键
            case 68: // D键
                this.moveItem(Direction.RIGHT);
                break;
            case 40: // 下箭头键
            case 83: // S键
                this.moveItem(Direction.DOWN);
                break;
        }
    }

    private onTouchStart(event: any) {
        if (this.panel == 0) return;
        this.posStart = event.getLocation();
    }

    private onTouchEnd(event: any) {
        if (this.panel == 0) return;
        this.posEnd = event.getLocation();
        this.checkMove();
    }

    private checkMove() {
        let _x = this.posEnd.x - this.posStart.x;
        let _y = this.posEnd.y - this.posStart.y;
        if (Math.abs(_x) < 5 && Math.abs(_y) < 5) {
            return;
        }
        if (Math.abs(_x) > Math.abs(_y)) {
            // x轴移动的值 > y轴移动的值 那么可能是左移或者右移
            if (_x > 0) {
                this.moveItem(Direction.RIGHT);
            } else {
                this.moveItem(Direction.LEFT);
            }
        } else {
            // 上下移动
            if (_y > 0) {
                this.moveItem(Direction.UP);
            } else {
                this.moveItem(Direction.DOWN);
            }
        }
    }

    private moveItem(direction: Direction) {
        let ismove: boolean = false;
        let getscore: boolean = false;
        if (direction == Direction.RIGHT) {
            // 右移
            for (let i = 0; i < this.grids; i++) {
                for (let j = this.grids - 2; j >= 0; j--) {
                    // j 列 比如有5列那么只有前4列 可以向右移动 下标为0 1 2 3
                    for (let k = 0; k < this.grids; k++) {
                        // k 表示移动的步数 比如有5列 只能移动1~4步
                        if (j + k + 1 < this.grids && this.data[i][j + k] > 0) {
                            if (this.data[i][j + k + 1] == 0) {
                                this.data[i][j + k + 1] = this.data[i][j + k];
                                this.data[i][j + k] = 0;
                                ismove = true;
                            } else if (this.data[i][j + k + 1] == this.data[i][j + k]) {
                                this.data[i][j + k + 1] = this.data[i][j + k] * 2;
                                this.data[i][j + k] = 0;
                                ismove = true;
                                getscore = true;
                                this.updateScore(this.data[i][j + k + 1]);
                                break;
                            }
                        }
                    }
                }
            }
        } else if (direction == Direction.LEFT) {
            // 左移
            console.log('左移')
            for (let i = 0; i < this.grids; i++) {
                for (let j = 1; j < this.grids; j++) {
                    // j 列 比如有5列那么只有前4列 可以向左移动 的 下标为 1 2 3 4
                    for (let k = 0; k < this.grids; k++) {
                        // k 表示移动的步数 比如有5列 只能移动1~4步
                        if (j - k - 1 >= 0 && this.data[i][j - k] > 0) {
                            if (this.data[i][j - k - 1] == 0) {
                                this.data[i][j - k - 1] = this.data[i][j - k];
                                this.data[i][j - k] = 0;
                                ismove = true;
                            } else if (this.data[i][j - k - 1] == this.data[i][j - k]) {
                                this.data[i][j - k - 1] = this.data[i][j - k] * 2;
                                this.data[i][j - k] = 0;
                                ismove = true;
                                getscore = true;
                                this.updateScore(this.data[i][j - k - 1]);
                                break;
                            }
                        }
                    }
                }
            }
        } else if (direction == Direction.UP) {
            // 上移
            console.log('上移')
            for (let i = 1; i < this.grids; i++) {
                for (let j = 0; j < this.grids; j++) {
                    // j 列 比如有5列那么只有前4列 可以向左移动 的 下标为 1 2 3 4
                    for (let k = 0; k < this.grids; k++) {
                        // k 表示移动的步数 比如有5列 只能移动1~4步
                        if (i - k - 1 >= 0 && this.data[i - k][j] > 0) {
                            if (this.data[i - k - 1][j] == 0) {
                                this.data[i - k - 1][j] = this.data[i - k][j];
                                this.data[i - k][j] = 0;
                                ismove = true;
                            } else if (this.data[i - k][j] == this.data[i - k - 1][j]) {
                                this.data[i - k - 1][j] = this.data[i - k][j] * 2;
                                this.data[i - k][j] = 0;
                                ismove = true;
                                getscore = true;
                                this.updateScore(this.data[i - k - 1][j]);
                                break;
                            }
                        }
                    }
                }
            }
        } else {
            // 下移
            console.log('下移')
            for (let i = this.grids - 2; i >= 0; i--) {
                for (let j = 0; j < this.grids; j++) {
                    // j 列 比如有5列那么只有前4列 可以向左移动 的 下标为 1 2 3 4
                    for (let k = 0; k < this.grids; k++) {
                        // k 表示移动的步数 比如有5列 只能移动1~4步
                        if (i + k + 1 < this.grids && this.data[i + k][j] > 0) {
                            if (this.data[i + k + 1][j] == 0) {
                                this.data[i + k + 1][j] = this.data[i + k][j];
                                this.data[i + k][j] = 0;
                                ismove = true;
                            } else if (this.data[i + k][j] == this.data[i + k + 1][j]) {
                                this.data[i + k + 1][j] = this.data[i + k][j] * 2;
                                this.data[i + k][j] = 0;
                                ismove = true;
                                getscore = true;
                                this.updateScore(this.data[i + k + 1][j]);
                                break;
                            }
                        }
                    }
                }
            }
        }
        if (ismove) {
            this.cleanAllItems();
            this.printGrid();
            for (let i = 0; i < this.grids; i++) {
                for (let j = 0; j < this.grids; j++) {
                    if (this.data[i][j] > 0) {
                        this.createItem(new Vec2(i, j), this.data[i][j], true)
                    }
                }
            }
            this.addRamdomArray();
        }
    }

    public printGrid() {
        // 控制台打印所有格子
        for (let i = 0; i < this.grids; i++) {
            let str = '';
            for (let j = 0; j < this.grids; j++) {
                str += this.data[i][j] + ' ';
            }
        }
    }

    private cleanAllItems() {
        // 一边循环一遍删除导致后面的下标全部不正确了
        /* let children = this.gridBg.children;
        for (let i = 0; i < children.length; i++) {
            let tile = children[i].getComponent(Tile);
            if (tile) {
                this.gridBg.removeChild(children[i]);
            }
        } */
        let childrenToRemove = [];
        let children = this.gridBg.children;

        // 先收集所有需要删除的节点
        for (let i = 0; i < children.length; i++) {
            let tile = children[i].getComponent(Tile);
            if (tile) {
                childrenToRemove.push(children[i]);
            }
        }

        // 再执行删除操作
        for (let i = 0; i < childrenToRemove.length; i++) {
            this.gridBg.removeChild(childrenToRemove[i]);
        }
    }

    private updateScore(score: number) {
        this.UserData.score += score;
        this.scoreLabel.string = this.UserData.score.toString();
        if (this.UserData.score > this.UserData.best) {
            this.UserData.best = this.UserData.score;
            this.bestLabel.string = this.UserData.best.toString();
        }
        this.saveUserInfo();
    }


    update(deltaTime: number) {

    }

    /**
     * 初始化游戏panel
     */
    private init() {
        this.panel = 1;
        this.getUserInfo();
        this.updateView();
    }

    private updateView() {
        this.scoreLabel.string = this.UserData.score.toString();
        this.bestLabel.string = this.UserData.best.toString();
        this.itemWidth = (this.gridWidth - this.jiange * (this.grids + 1)) / this.grids;
        this.gridBgUITransform.width = this.gridWidth;
        this.gridBgUITransform.height = this.gridWidth;
        this.addItembg(this.grids)

        this.initData(this.grids)
        this.addRamdomArray();
    }

    /**
     * 随机添加一个格子
     */
    private addRamdomArray() {
        // 获取空格子数组
        let emptyArray = [];
        // 获取空格子对应的下标数组
        let emptyIndexArray = [];
        for (let i = 0; i < this.data.length; i++) {
            for (let j = 0; j < this.data.length; j++) {
                if (this.data[i][j] == 0) {
                    emptyArray.push(this.data[i][j]);
                    emptyIndexArray.push(new Vec2(i, j));
                }
            }
        }
        if (emptyArray.length > 0) {
            let index = Math.floor(Math.random() * emptyArray.length);
            let i = emptyIndexArray[index].x;
            let j = emptyIndexArray[index].y;
            this.data[i][j] = Math.random() * 10 < 2 ? 4 : 2;
            this.createItem(emptyIndexArray[index], this.data[i][j], true);
        }
    }

    /**
     * 随机添加一个格子
     */
    private createItem(pos: Vec2, num: number, isAction: boolean = false) {
        let posStart = new Vec2(-this.gridWidth / 2 + this.jiange + this.itemWidth / 2,
            this.gridWidth / 2 - this.jiange - this.itemWidth / 2);
        // 实例化格子预制体
        let item = instantiate(this.grid);
        let tile = item.getComponent(Tile);
        if (tile) {
            tile.init(num);
        }
        // 设置父节点
        item.parent = this.gridBg;
        let itemBgTf: UITransform = item.getComponent(UITransform);
        itemBgTf.setContentSize(this.itemWidth, this.itemWidth);
        // 修正坐标计算
        const x = posStart.x + (this.itemWidth + this.jiange) * pos.y;
        const y = posStart.y - (this.itemWidth + this.jiange) * pos.x;
        item.setPosition(x, y);
        if (isAction) {
            item.setScale(0, 0, 0);
            new Tween(item).to(0.15, { scale: new Vec3(1, 1, 1) }, { easing: easing.sineInOut }).start();
        }
        this.printGrid();
    }

    /**
     * 初始化数据
     * @param num 
     */
    private initData(num: number = 0) {
        this.data = [];
        for (let i = 0; i < num; i++) {
            this.data[i] = [];
        }
        for (let i = 0; i < num; i++) {
            for (let j = 0; j < num; j++) {
                this.data[i][j] = 0
            }
        }
    }

    /**
     * 生成格子背景
     * @param num 
     */
    private addItembg(num: number = 0) {
        // 获取左上角第一个格子中心点的坐标
        let posStart = new Vec2(-this.gridWidth / 2 + this.jiange + this.itemWidth / 2,
            this.gridWidth / 2 - this.jiange - this.itemWidth / 2);
        for (let i = 0; i < num; i++) {
            for (let j = 0; j < num; j++) {
                let itembg = instantiate(this.gridbg);
                itembg.parent = this.gridBg;
                let itemBgTf: UITransform = itembg.getComponent(UITransform);
                itemBgTf.setContentSize(this.itemWidth, this.itemWidth);
                itembg.setPosition(posStart.x + (itemBgTf.width + this.jiange) * i,
                    posStart.y - (itemBgTf.height + this.jiange) * j);
                // console.log('第' + (i + 1) + '行，第' + (j + 1) + '列的格子的坐标为：', itembg.getPosition().x, itembg.getPosition().y)
            }
        }
    }

    private getUserInfo() {
        this.UserData = JSON.parse(localStorage.getItem("UserData"));
        if (this.UserData == null) {
            this.UserData = {
                level: 5,
                score: 0,
                best: 0,
                grid: [],
                histiry: []
            }
        }
    }

    private saveUserInfo() {
        localStorage.setItem("UserData", JSON.stringify(this.UserData));
    }

    private initPanel() {
        this.startPanel.active = false;
        this.gamePanel.active = false;
    }

    private onButtonClick() {
        this.startPanel.active = false;
        this.gamePanel.active = true;
        this.init();
    }
}


